﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using AMRService.DAL;
using AMRService.IDAL;
using AMRService.Models.ResponseModels.ModelHelper.Common;
using Driverplugin;
using Google.Protobuf;
using static Driverplugin.DeviceStatus.Types;
using System.Linq;
namespace IoTEdge.Grpc.Server.Libs.entities
{
    public class DeviceModel
    {
        public DeviceMeta DeviceMeta { get; set; }
        public CancellationTokenSource TokenSource { get; set; } = new();
        public int Interval { get; set; }
        public int Timeout { get; set; }
        public Action<DeviceModel, Driverplugin.Data> SendMessage { get; set; }
        public Action<DeviceModel, DeviceState, string> ReportErr { get; set; }
        public IAmrService AmrCollect { get; set; } = new AmrService();
        public CustomProtocolModel CustomProtocolModel { get; set; }
        public void run()
        {
            _ = Task.Factory.StartNew(async (x) =>
            {
                var source = x as CancellationTokenSource;
                bool firston = false;
                do
                {
                    if (!firston)
                    {
                        await Task.Delay(1000);
                        firston = true;
                    }
                    else
                    {
                        await Task.Delay(5000);
                    }

                    try
                    {
                        if (!source.Token.IsCancellationRequested)
                            ReportErr?.Invoke(this, DeviceState.OnlineState, "NoErr");
                        else
                        {
                            ReportErr?.Invoke(this, DeviceState.OfflineState, "Stopped");
                            return;
                        }
                    }
                    catch (Exception)
                    {
                        break;
                    }

                } while (true);
            }, TokenSource);

            Task.Factory.StartNew(async (x) =>
            {
                var token = x as CancellationTokenSource;
                while (true)
                {
                    if (token.Token.IsCancellationRequested)
                        break;
                    await Task.Delay(Interval);
                    Root<List<AMRService.Models.ResponseModels.ModelHelper.Common.Data>>? data = null;
                    try
                    {
                        data = await AmrCollect.AmrOnLine($"http://{CustomProtocolModel.IP}:{CustomProtocolModel.Port}", "/api/amr/onlineAmr", new Dictionary<string, string>()
                    {
                        {"Name",$"{CustomProtocolModel.User}" },
                        {"Token",$"{CustomProtocolModel.Password}" },
                    }).WaitAsync(TimeSpan.FromMilliseconds(Timeout));
                    }
                    catch (Exception exp)
                    {
                        data = null;
                        ReportErr?.Invoke(this, DeviceState.ErrorState, exp.Message);
                        break;
                    }
                    if (!data.state)
                    {
                        ReportErr?.Invoke(this, DeviceState.ErrorState, "发生错误，请检查设置！");
                        break;
                    }
                    if (data != null && data.data != null && data.data.Count < 1)
                    {
                        ReportErr?.Invoke(this, DeviceState.ErrorState, "已连接到Amr服务器，但是未发现任何在线设备！");
                        break;
                    }
                    UpdateDataToIoTEdge dax = new UpdateDataToIoTEdge();
                    UpdateDataToIoTEdge updatedata = new UpdateDataToIoTEdge();
                    updatedata.ts = DateTimeOffset.Now.DateTime.ToString($"yyyy-MM-dd{"T"}HH:mm:ss.fff:+0800");
                    updatedata.p_id = DeviceMeta.Defination.ProductID;
                    updatedata.d_id = DeviceMeta.Defination.DeviceID;
                    CustomModule cos = new CustomModule();
                    foreach (var item1 in DeviceMeta.Defination.Properties.ToArray())
                    {
                        if (token.Token.IsCancellationRequested)
                            return;
                        if (!updatedata.services.ContainsKey(item1.Service))
                            updatedata.services.Add(item1.Service, cos);
                        var temp1 = JsonSerializer.Deserialize<PropertyExtensionConfig>(item1.PropertyExtensionConfig);
                        cos.properties.Add(item1.Property,
                            new CustomProperty() { value = GetValue(data, temp1.Address), dataType = item1.PropertyType.ToString() });
                    }
                    if (!token.Token.IsCancellationRequested)
                        SendMessage?.Invoke(this, new Driverplugin.Data() { Datas = ByteString.CopyFrom(Encoding.UTF8.GetBytes(JsonSerializer.Serialize(updatedata))) });
                }
            }, TokenSource);
        }
        // 根据协议配置文件，获取对应的数据
        public object GetValue(Root<List<AMRService.Models.ResponseModels.ModelHelper.Common.Data>>? data, string value)
        {
            switch (value)
            {
                case "1":
                    return data.data[0].id;
                case "2":
                    return data.data[0].name;
                case "3":
                    return data.data[0].ip;
                case "4":
                    return data.data[0].mapName;
                case "5":
                    return data.data[0].batteryPercentile;
                case "6":
                    return data.data[0].coordinate.x;
                case "7":
                    return data.data[0].coordinate.y;
                case "8":
                   var ps = data.data[0].lockedPoint;
                    StringBuilder sb = new StringBuilder();
                    for (int i = 0; i < ps.Count; i++)
                    {
                        sb.Append(ps[i]+";");
                    }
                    return sb.ToString();
                case "9":
                    return ((data.data[0].coordinate.theta)*180.0)/Math.PI;
                case "10":
                    return data.data[0].amrException.ToString();
                case "11":
                    return data.data[0].amrException.level;
                case "12":
                    return data.data[0].amrException.exceptionCodes != null ? data.data[0].amrException.exceptionCodes.Count > 0 ? data.data[0].amrException.exceptionCodes[0] : "No Codes" : "No Codes";
                case "13":
                    return data.data[0].state;
                case "14":
                    return data.data[0].areaId;
                case "15":
                    return data.data[0].stateId;
                case "16":
                    return data.data[0].mapId;
                case "17":
                    return data.data[0].materials.present;
                case "18":
                    return data.data[0].stateId == 3 ? "正在充电" : "未充电";
                case "19":
                    return data.data[0].velocity.vx;
                default:
                    return "unknown";
            }
        }
    }
}
